home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue31 / bcolorbt / BCOLORBT.ZIP / CBtnForm.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-02-06  |  20.8 KB  |  781 lines

  1. {.$DEFINE FIX_STREAM_ERROR}
  2.  
  3. {$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }
  4.  
  5. {-----------------------------------------------------------------------------}
  6. { A Windows 95 and NT 4 style color selection button.  It displays a palette  }
  7. { of 20 color for fast selction and a button to bring up the color dialog.    }
  8. { Copyright 1996, Brad Stowers.  All Rights Reserved.                         }
  9. { This component can be freely used and distributed in commercial and private }
  10. { environments, provied this notice is not modified in any way and there is   }
  11. { no charge for it other than nomial handling fees.  Contact me directly for  }
  12. { modifications to this agreement.                                            }
  13. {-----------------------------------------------------------------------------}
  14. { Feel free to contact me if you have any questions, comments or suggestions  }
  15. { at bstowers@pobox.com.                                                      }
  16. { The lateset version will always be available on the web at:                 }
  17. {   http://www.pobox.com/~bstowers/delphi/                                    }
  18. {-----------------------------------------------------------------------------}
  19. { Date last modified:  February 5, 1998                                       }
  20. {-----------------------------------------------------------------------------}
  21.  
  22.  
  23. {-----------------------------------------------------------------------------}
  24. { TDFSColorButtonPalette                                                      }
  25. {-----------------------------------------------------------------------------}
  26. { Description:                                                                }
  27. {   This is a support unit for the TDFSColorButton component (COLORBTN.PAS).  }
  28. {-----------------------------------------------------------------------------}
  29. unit CBtnForm;
  30.  
  31. interface
  32.  
  33. uses
  34.   WinTypes, WinProcs, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  35.   Dialogs, StdCtrls;
  36.  
  37. const
  38.   MAX_COLORS = (MaxInt div SizeOf(TColor));
  39.  
  40. type
  41.   TSetParentColorEvent = procedure(Sender: TObject; AColor: TColor) of object;
  42.  
  43.   EColorArrayIndexError = class(Exception);
  44.  
  45.   PColorArray = ^TColorArray;
  46.   TColorArray = array[1..MAX_COLORS] of TColor;
  47.  
  48.   TColorArrayClass = class(TPersistent)
  49.   private
  50.     FXSize,
  51.     FYSize: integer;
  52.     FColors: PColorArray;
  53.  
  54.     function GetColor(X, Y: integer): TColor;
  55.     procedure SetColor(X, Y: integer; Value: TColor);
  56.     procedure SetXSize(Value: integer);
  57.     procedure SetYSize(Value: integer);
  58.     function GetSingleColor(Index: integer): TColor;
  59.     procedure SetSingleColor(Index: integer; Value: TColor);
  60.   protected
  61.     procedure CheckXYVals(X, Y: integer);
  62. {$IFDEF FIX_STREAM_ERROR}
  63.     procedure ReadColorData(Stream: TStream);
  64.     procedure WriteColorData(Stream: TStream);
  65. {$ELSE}
  66.     procedure ReadColors(Reader: TReader);
  67.     procedure WriteColors(Writer: TWriter);
  68. {$ENDIF}
  69.   public
  70.     constructor Create(X, Y: integer); virtual;
  71.     destructor Destroy; override;
  72.     procedure Assign(Source: TPersistent); override;
  73.     procedure DefineProperties(Filer: TFiler); override;
  74.     function IsEqualTo(OtherColors: TColorArrayClass): boolean; virtual;
  75.  
  76.     property Color[X: integer; Y: integer]: TColor
  77.        read GetColor
  78.        write SetColor;
  79.        default;
  80.     property Colors[Index: integer]: TColor
  81.       read GetSingleColor
  82.       write SetSingleColor;
  83. {  published}
  84.     property XSize: integer
  85.        read FXSize
  86.        write SetXSize;
  87.     property YSize: integer
  88.        read FYSize
  89.        write SetYSize;
  90.   end;
  91.  
  92.   TPaletteColors = TColorArrayClass;
  93.   TCustomColors = TColorArrayClass;
  94.  
  95.   TDFSColorButtonPalette = class(TForm)
  96.     btnOther: TButton;
  97.     procedure FormClose(Sender: TObject; var Action: TCloseAction);
  98.     procedure FormDeactivate(Sender: TObject);
  99.     procedure FormPaint(Sender: TObject);
  100.     procedure FormCreate(Sender: TObject);
  101.     procedure btnOtherClick(Sender: TObject);
  102.     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  103.     procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X,
  104.       Y: Integer);
  105.     procedure FormClick(Sender: TObject);
  106.     procedure FormKeyPress(Sender: TObject; var Key: Char);
  107.     procedure FormDestroy(Sender: TObject);
  108.   private
  109.     FPreventClose: boolean;
  110.     FOldAppDeactivate: TNotifyEvent;
  111.     FPaletteColors: TPaletteColors;
  112.     FCustomColors: TCustomColors;
  113.     FStartColor,
  114.     FOtherColor: TColor;
  115.     FLastFrame: TPoint;
  116.     FSetParentColor: TSetParentColorEvent;
  117.     FPaletteClosed: TNotifyEvent;
  118.  
  119.     function ValidColorIndex(X, Y: integer): boolean;
  120.     procedure AppDeactivate(Sender: TObject);
  121.     procedure DrawSquare(X, Y: integer; AColor: TColor; IsFocused: boolean);
  122.     procedure FrameCurrentSquare;
  123.     function GetCurrentSquare: TPoint;
  124.     procedure SetStartColor(Value: TColor);
  125.     procedure SetPaletteColors(Value: TPaletteColors);
  126.     procedure SetCustomColors(Value: TCustomColors);
  127.   protected
  128.     procedure CreateParams(var Params: TCreateParams); override;
  129.   public
  130.     constructor Create(AOwner: TComponent); override;
  131.     destructor Destroy; override;
  132.  
  133.     property SetParentColor: TSetParentColorEvent
  134.        read FSetParentColor
  135.        write FSetParentColor;
  136.     property PaletteClosed: TNotifyEvent
  137.        read FPaletteClosed
  138.        write FPaletteClosed;
  139.     property Color: TColor
  140.        read FStartColor
  141.        write SetStartColor;
  142.     property OtherColor: TColor
  143.        read FOtherColor
  144.        write FOtherColor;
  145.     property PaletteColors: TPaletteColors
  146.        read FPaletteColors
  147.        write SetPaletteColors;
  148.     property CustomColors: TCustomColors
  149.        read FCustomColors
  150.        write SetCustomColors;
  151.   end;
  152.  
  153.  
  154. implementation
  155.  
  156. {$R *.DFM}
  157.  
  158.  
  159. constructor TColorArrayClass.Create(X, Y: integer);
  160. begin
  161.   inherited Create;
  162.  
  163.   FXSize := X;
  164.   FYSize := Y;
  165.   GetMem(FColors, X * Y * SizeOf(TColor));
  166. end;
  167.  
  168. destructor TColorArrayClass.Destroy;
  169. begin
  170.   FreeMem(FColors, FXSize * FYSize * SizeOf(TColor));
  171.  
  172.   inherited Destroy;
  173. end;
  174.  
  175. function TColorArrayClass.GetColor(X, Y: integer): TColor;
  176. begin
  177.   CheckXYVals(X, Y);
  178.   Result := FColors^[(Y-1)*FXSize+X];
  179. end;
  180.  
  181. procedure TColorArrayClass.SetColor(X, Y: integer; Value: TColor);
  182. begin
  183.   CheckXYVals(X, Y);
  184.   FColors^[(Y-1)*FXSize+X] := Value;
  185. end;
  186.  
  187. procedure TColorArrayClass.SetXSize(Value: integer);
  188. begin
  189.   if Value <> XSize then
  190.   begin
  191.     FreeMem(FColors, XSize * YSize * SizeOf(TColor));
  192.     FXSize := Value;
  193.     GetMem(FColors, XSize * YSize * SizeOf(TColor));
  194.     { really need to recopy colors, but I'm lazy and don't need it right now }
  195.   end;
  196. end;
  197.  
  198. procedure TColorArrayClass.SetYSize(Value: integer);
  199. begin
  200.   if Value <> YSize then
  201.   begin
  202.     FreeMem(FColors, XSize * YSize * SizeOf(TColor));
  203.     FYSize := Value;
  204.     GetMem(FColors, XSize * YSize * SizeOf(TColor));
  205.     { really need to recopy colors, but I'm lazy and don't need it right now }
  206.   end;
  207. end;
  208.  
  209. function TColorArrayClass.GetSingleColor(Index: integer): TColor;
  210. begin
  211.   if (Index < 1) or (Index > (XSize * YSize)) then
  212.     raise EColorArrayIndexError.Create('Array index out of bounds');
  213.   Result := FColors^[Index];
  214. end;
  215.  
  216. procedure TColorArrayClass.SetSingleColor(Index: integer; Value: TColor);
  217. begin
  218.   if (Index < 1) or (Index > (XSize * YSize)) then
  219.     raise EColorArrayIndexError.Create('Array index out of bounds');
  220.   if FColors^[Index] <> Value then
  221.     FColors^[Index] := Value;
  222. end;
  223.  
  224. procedure TColorArrayClass.CheckXYVals(X, Y: integer);
  225. begin
  226.   if (X < 1) or (Y < 1) or (X > XSize) or (Y > YSize) then
  227.     raise EColorArrayIndexError.Create('Array index out of bounds');
  228. end;
  229.  
  230.  
  231. {$IFDEF FIX_STREAM_ERROR}
  232. const
  233.   STREAM_SIG = $DF5;
  234.  
  235. procedure TColorArrayClass.ReadColorData(Stream: TStream);
  236. var
  237.   Sig: integer;
  238.   X, Y: integer;
  239.   AColor: TColor;
  240. begin
  241.   Stream.ReadBuffer(Sig, sizeof(Sig));
  242.   if Sig = STREAM_SIG then
  243.   begin
  244.     Stream.ReadBuffer(X, sizeof(X));
  245.     XSize := X;
  246.     Stream.ReadBuffer(Y, sizeof(Y));
  247.     YSize := Y;
  248.     for X := 1 to XSize do
  249.       for Y := 1 to YSize do
  250.       begin
  251.         Stream.ReadBuffer(AColor, SizeOf(TColor));
  252.         Color[X, Y] := AColor;
  253.       end;
  254.   end;
  255. end;
  256.  
  257. procedure TColorArrayClass.WriteColorData(Stream: TStream);
  258. var
  259.   X, Y: integer;
  260.   AColor: TColor;
  261. begin
  262.   X := XSize;
  263.   Stream.WriteBuffer(X, SizeOf(X));
  264.   Y := YSize;
  265.   Stream.WriteBuffer(Y, SizeOf(Y));
  266.   for X := 1 to XSize do
  267.     for Y := 1 to YSize do
  268.     begin
  269.       AColor := Color[X, Y];
  270.       Stream.WriteBuffer(AColor, SizeOf(TColor));
  271.     end;
  272. end;
  273.  
  274. {$ELSE}
  275.  
  276. procedure TColorArrayClass.ReadColors(Reader: TReader);
  277. var
  278.   X, Y: integer;
  279.   AColor: TColor;
  280. begin
  281.   XSize := Reader.ReadInteger;
  282.   YSize := Reader.ReadInteger;
  283.   for X := 1 to XSize do
  284.     for Y := 1 to YSize do
  285.     begin
  286.       Reader.Read(AColor, SizeOf(TColor));
  287.       Color[X, Y] := AColor;
  288.     end;
  289. end;
  290.  
  291. procedure TColorArrayClass.WriteColors(Writer: TWriter);
  292. var
  293.   X, Y: integer;
  294.   AColor: TColor;
  295. begin
  296.   Writer.WriteInteger(XSize);
  297.   Writer.WriteInteger(YSize);
  298.   for X := 1 to XSize do
  299.     for Y := 1 to YSize do
  300.     begin
  301.       AColor := Color[X, Y];
  302.       Writer.Write(AColor, SizeOf(TColor));
  303.     end;
  304. end;
  305.  
  306. {$ENDIF}
  307.  
  308. procedure TColorArrayClass.DefineProperties(Filer: TFiler);
  309. begin
  310.   inherited DefineProperties(Filer);
  311. {$IFDEF FIX_STREAM_ERROR}
  312.   Filer.DefineBinaryProperty('SavedColors', ReadColorData, WriteColorData, TRUE);
  313. {$ELSE}
  314.   Filer.DefineProperty('SavedColors', ReadColors, WriteColors, TRUE);
  315. {$ENDIF}
  316. end;
  317.  
  318. procedure TColorArrayClass.Assign(Source: TPersistent);
  319. var
  320.   x, y: integer;
  321. begin
  322.   if Source is TColorArrayClass then
  323.   begin
  324.     FreeMem(FColors, XSize * YSize * SizeOf(TColor));
  325.     FXSize := TColorArrayClass(Source).XSize;
  326.     FYSize := TColorArrayClass(Source).YSize;
  327.     GetMem(FColors, XSize * YSize * SizeOf(TColor));
  328.     for x := 1 to XSize do
  329.     begin
  330.       for y := 1 to YSize do
  331.       begin
  332.         Color[x,y] := TColorArrayClass(Source).Color[x,y];
  333.       end;
  334.     end;
  335.   end else
  336.     inherited Assign(Source);
  337. end;
  338.  
  339. function TColorArrayClass.IsEqualTo(OtherColors: TColorArrayClass): boolean;
  340. var
  341.   x, y: integer;
  342. begin
  343.   Result := FALSE;
  344.   if OtherColors = Self then
  345.   begin
  346.     Result := TRUE;
  347.     exit;
  348.   end;
  349.   if OtherColors <> NIL then
  350.   begin
  351.     if (XSize = OtherColors.XSize) and (YSize = OtherColors.YSize) then
  352.     begin
  353.       for x := 1 to XSize do
  354.       begin
  355.         for y := 1 to YSize do
  356.         begin
  357.           if Color[x,y] <> OtherColors.Color[x,y] then
  358.             exit;
  359.         end;
  360.       end;
  361.       Result := TRUE;  { all colors matched }
  362.     end;
  363.   end;
  364. end;
  365.  
  366.  
  367.  
  368.  
  369.  
  370. constructor TDFSColorButtonPalette.Create(AOwner: TComponent);
  371. begin
  372.   { Inherited is going to fire FormCreate which needs the colors, so create our
  373.     stuff before calling inherited. }
  374.   FPaletteColors := TColorArrayClass.Create(4,5);
  375.   FCustomColors := TColorArrayClass.Create(8,2);
  376.  
  377.   inherited Create(AOwner);
  378. end;
  379.  
  380. destructor TDFSColorButtonPalette.Destroy;
  381. begin
  382.   FPaletteColors.Free;
  383.   FCustomColors.Free;
  384.  
  385.   inherited Destroy;
  386. end;
  387.  
  388. procedure TDFSColorButtonPalette.CreateParams(var Params: TCreateParams);
  389. begin
  390.   inherited CreateParams(Params);
  391. {$IFDEF DFS_WIN32}
  392.   Params.Style := Params.Style AND NOT WS_CAPTION;
  393. {$ELSE}
  394.   Params.Style := WS_POPUP or WS_DLGFRAME or DS_MODALFRAME;
  395. {$ENDIF}
  396. end;
  397.  
  398. procedure TDFSColorButtonPalette.FormClose(Sender: TObject;
  399.   var Action: TCloseAction);
  400. begin
  401.   Action := caFree;
  402.   if assigned(FPaletteClosed) then
  403.     FPaletteClosed(Self);
  404. end;
  405.  
  406. procedure TDFSColorButtonPalette.FormDeactivate(Sender: TObject);
  407. begin
  408.   Close;
  409. end;
  410.  
  411. procedure TDFSColorButtonPalette.FormPaint(Sender: TObject);
  412. var
  413.   X, Y: integer;
  414. begin
  415.   for X := 1 to 4 do
  416.   begin
  417.     for Y := 1 to 5 do
  418.     begin
  419.       { Draw color square }
  420.       DrawSquare(X, Y, FPaletteColors[x,y], FALSE);
  421.     end;
  422.   end;
  423.  
  424.   { Draw seperator line }
  425.   with Canvas do
  426.   begin
  427.     Pen.Color := clBtnShadow;
  428.     MoveTo(2, 93);
  429.     LineTo(ClientWidth - 2, 93);
  430.     Pen.Color := clBtnHighlight;
  431.     MoveTo(2, 94);
  432.     LineTo(ClientWidth - 2, 94);
  433.   end;
  434.  
  435.   { Draw "other" color }
  436.   DrawSquare(0, 0, FOtherColor, FALSE);
  437.  
  438.   { Draw the current selection }
  439.   FrameCurrentSquare;
  440. end;
  441.  
  442. procedure TDFSColorButtonPalette.DrawSquare(X, Y: integer; AColor: TColor; IsFocused: boolean);
  443. begin
  444.   if (X = 0) and (Y = 0) then
  445.   begin
  446.     { other square }
  447.     X := ClientWidth - 18;
  448.     Y := 97;
  449.     AColor := FOtherColor;
  450.   end else if ValidColorIndex(X, Y) then
  451.   begin
  452.     X := (X-1) * 18 + 2;
  453.     Y := (Y-1) * 18 + 2;
  454.   end else
  455.     exit;
  456.  
  457.   with Canvas do
  458.   begin
  459.     if IsFocused then
  460.       Pen.Color := clBlack
  461.     else
  462.       Pen.Color := clBtnFace;
  463.     MoveTo(X-1,Y-1);
  464.     LineTo(X+16, Y-1);
  465.     LineTo(X+16, Y+16);
  466.     LineTo(X-1, Y+16);
  467.     LineTo(X-1, Y-1);
  468.  
  469.     if IsFocused then
  470.     begin
  471.       { Draw frame }
  472.       MoveTo(X+1, Y+1);
  473.       LineTo(X+14, Y+1);
  474.       LineTo(X+14, Y+14);
  475.       LineTo(X+1, Y+14);
  476.       LineTo(X+1, Y+1);
  477.       Pen.Color := clWhite;
  478.       MoveTo(X, Y);
  479.       LineTo(X+15, Y);
  480.       LineTo(X+15, Y+15);
  481.       LineTo(X, Y+15);
  482.       LineTo(X, Y);
  483.     end else begin
  484.       Pen.Color := clGray;
  485.       MoveTo(X, Y+15);
  486.       LineTo(X, Y);
  487.       LineTo(X+15, Y);
  488.       Pen.Color := clWhite;
  489.       LineTo(X+15, Y+15);
  490.       LineTo(X, Y+15);
  491.       Pen.Color := clBlack;
  492.       MoveTo(X+1, Y+14);
  493.       LineTo(X+1, Y+1);
  494.       LineTo(X+14, Y+1);
  495.       Pen.Color := RGB(223, 223, 223);
  496.       LineTo(X+14, Y+14);
  497.       LineTo(X+1, Y+14);
  498.     end;
  499.  
  500.     Brush.Color := AColor;
  501.     FillRect(Rect(X+2, Y+2, X+14, Y+14));
  502.   end;
  503. end;
  504.  
  505. function ColorEnumProc(Pen: PLogPen; var Colors: array of TColorRef): integer;
  506.    {$IFDEF DFS_WIN32} stdcall; {$ELSE} export; {$ENDIF}
  507. begin
  508.   if Pen^.lopnStyle = PS_SOLID then
  509.   begin
  510.     if Colors[0] < 20 then
  511.     begin
  512.       inc(Colors[0]);
  513.       Colors[Colors[0]] := Pen^.lopnColor;
  514.       Result := 1;
  515.     end else
  516.       Result := 0;
  517.   end else
  518.     Result := 1;
  519. end;
  520.  
  521. procedure TDFSColorButtonPalette.FormCreate(Sender: TObject);
  522. var
  523.   X, Y: integer;
  524.   Colors: array[0..20] of TColorRef;
  525.   DC: HDC;
  526. begin
  527.   FPreventClose := FALSE;
  528.   FOldAppDeactivate := Application.OnDeactivate;
  529.   Application.OnDeactivate := AppDeactivate;
  530.   FLastFrame := Point(-1,-1);
  531.  
  532.   DC := GetDC(GetDesktopWindow);
  533.   try
  534.     if GetDeviceCaps(DC, NUMCOLORS) = 16 then
  535.     begin
  536.       { 16 color mode, enum colors to fill array }
  537.       FillChar(Colors, SizeOf(Colors), #0);
  538.       EnumObjects(DC, OBJ_PEN, @ColorEnumProc,
  539.          {$IFDEF DFS_WIN32} LPARAM(@Colors) {$ELSE} @Colors {$ENDIF});
  540.       for X := 1 to 4 do
  541.       begin
  542.         for Y := 1 to 5 do
  543.         begin
  544.           FPaletteColors[X,Y] := Colors[(X-1)*5+Y];
  545.         end;
  546.       end;
  547.     end else begin
  548.       { Lots 'o colors, pick the ones we want. }
  549.       FPaletteColors[1,1] := RGB(255,255,255);
  550.       FPaletteColors[1,2] := RGB(255,0,0);
  551.       FPaletteColors[1,3] := RGB(0,255,0);
  552.       FPaletteColors[1,4] := RGB(0,0,255);
  553.       FPaletteColors[1,5] := RGB(191,215,191);
  554.       FPaletteColors[2,1] := RGB(0,0,0);
  555.       FPaletteColors[2,2] := RGB(127,0,0);
  556.       FPaletteColors[2,3] := RGB(0,127,0);
  557.       FPaletteColors[2,4] := RGB(0,0,127);
  558.       FPaletteColors[2,5] := RGB(159,191,239);
  559.       FPaletteColors[3,1] := RGB(191,191,191);
  560.       FPaletteColors[3,2] := RGB(255,255,0);
  561.       FPaletteColors[3,3] := RGB(0,255,255);
  562.       FPaletteColors[3,4] := RGB(255,0,255);
  563.       FPaletteColors[3,5] := RGB(255,247,239);
  564.       FPaletteColors[4,1] := RGB(127,127,127);
  565.       FPaletteColors[4,2] := RGB(127,127,0);
  566.       FPaletteColors[4,3] := RGB(0,127,127);
  567.       FPaletteColors[4,4] := RGB(127,0,127);
  568.       FPaletteColors[4,5] := RGB(159,159,159);
  569.     end;
  570.   finally
  571.     ReleaseDC(GetDesktopWindow, DC);
  572.   end;
  573.  
  574.   FOtherColor := clBtnFace;
  575.   FStartColor := clBlack;
  576. end;
  577.  
  578. procedure TDFSColorButtonPalette.SetStartColor(Value: TColor);
  579. var
  580.   x, y: integer;
  581. begin
  582.   FStartColor := Value;
  583.   { See if we have that color }
  584.   for x := 1 to 4 do
  585.   begin
  586.     for y := 1 to 5 do
  587.     begin
  588.       if ColorToRGB(FPaletteColors[x,y]) = ColorToRGB(FStartColor) then
  589.       begin
  590.         FLastFrame := Point(x,y);
  591.         DrawSquare(x, y, FStartColor, TRUE);
  592.         exit;
  593.       end;
  594.     end;
  595.   end;
  596.   { didn't find it }
  597.   FOtherColor := FStartColor;
  598. end;
  599.  
  600. procedure TDFSColorButtonPalette.AppDeactivate(Sender: TObject);
  601. begin
  602.   if FPreventClose then
  603.     exit;
  604.  
  605.   if assigned(FOldAppDeactivate) then
  606.     FOldAppDeactivate(Sender);
  607.   Close;
  608. end;
  609.  
  610. procedure TDFSColorButtonPalette.btnOtherClick(Sender: TObject);
  611. var
  612.   AColor: TColor;
  613.   c: char;
  614.   p: integer;
  615.   y: integer;
  616.   x: integer;
  617.   z: integer;
  618.   Dlg: TColorDialog;
  619.   ColorPicked: boolean;
  620. begin
  621.   Dlg := TColorDialog.Create(Self);
  622.   try
  623.     FPreventClose := TRUE;
  624.     Dlg.Color := FOtherColor;
  625.     Dlg.Options := [cdFullOpen];
  626.     { set custom colors here }
  627.     for x := 1 to 8 do
  628.     begin
  629.       for y := 1 to 2 do
  630.       begin
  631.         c := Chr((y-1)*8+x + 64);
  632.         Dlg.CustomColors.Add('Color' + c + '=' + IntToHex(CustomColors[x,y], 8));
  633.       end;
  634.     end;
  635.     ColorPicked := Dlg.Execute;
  636.     if ColorPicked then
  637.     begin
  638.       FOtherColor := Dlg.Color;
  639.       { get custom colors here }
  640.       for z := 0 to 15 do
  641.       begin
  642.         p := Pos('=', Dlg.CustomColors[z]);
  643.         AColor := StrToIntDef('$'+Copy(Dlg.CustomColors[z], p+1, 9), clWhite);
  644.         p := Ord(Dlg.CustomColors[z][p-1]) - 64;
  645.         x := (p-1) mod 8 + 1;
  646.         y := (p-1) div 8 + 1;
  647.         CustomColors[x,y] := AColor;
  648.       end;
  649.     end;
  650.   finally
  651.     FPreventClose := FALSE;
  652.     Dlg.Free;
  653.   end;
  654.  
  655.   if ColorPicked then
  656.   begin
  657.     if assigned(FSetParentColor) then
  658.       FSetParentColor(Self, FOtherColor);
  659.     Close;
  660.   end;
  661. end;
  662.  
  663. procedure TDFSColorButtonPalette.FormCloseQuery(Sender: TObject;
  664.   var CanClose: Boolean);
  665. begin
  666.   CanClose := not FPreventClose;
  667. end;
  668.  
  669. function TDFSColorButtonPalette.ValidColorIndex(X, Y: integer): boolean;
  670. begin
  671.   Result := ((X > 0) and (X <= 4) and (Y > 0) and (Y <= 5)) or ((X = 0) and (Y = 0));
  672. end;
  673.  
  674. procedure TDFSColorButtonPalette.FrameCurrentSquare;
  675.  
  676.   function ComparePoints(const Pt1, Pt2: TPoint): boolean;
  677.   begin
  678.     Result := ((Pt1.X = Pt2.X) and (Pt1.Y =Pt2.Y));
  679.   end;
  680.  
  681. var
  682.   NewFrame: TPoint;
  683.   AColor: TColor;
  684. begin
  685.   NewFrame := GetCurrentSquare;
  686.   if not ComparePoints(NewFrame, FLastFrame) and
  687.      ValidColorIndex(NewFrame.X, NewFrame.Y) then
  688.   begin
  689.     { Unframe the last one }
  690.     if ValidColorIndex(FLastFrame.X, FLastFrame.Y) then
  691.     begin
  692.       if ComparePoints(FLastFrame, Point(0,0)) then
  693.         AColor := FOtherColor
  694.       else
  695.         AColor := FPaletteColors[FLastFrame.X, FLastFrame.Y];
  696.       with FLastFrame do
  697.         DrawSquare(X, Y, AColor, FALSE);
  698.     end;
  699.  
  700.         if ComparePoints(NewFrame, Point(0,0)) then
  701.       AColor := FOtherColor
  702.     else
  703.       AColor := FPaletteColors[NewFrame.X, NewFrame.Y];
  704.     with NewFrame do
  705.       DrawSquare(X, Y, AColor, TRUE);
  706.     FLastFrame := NewFrame;
  707.   end;
  708. end;
  709.  
  710.  
  711. procedure TDFSColorButtonPalette.FormMouseMove(Sender: TObject;
  712.   Shift: TShiftState; X, Y: Integer);
  713. begin
  714.   FrameCurrentSquare;
  715. end;
  716.  
  717. procedure TDFSColorButtonPalette.FormClick(Sender: TObject);
  718. var
  719.   SelectedColorSquare: TPoint;
  720.   AColor: TColor;
  721. begin
  722.   if assigned(FSetParentColor) then
  723.   begin
  724.     SelectedColorSquare := GetCurrentSquare;
  725.     if ValidColorIndex(SelectedColorSquare.X, SelectedColorSquare.Y) then
  726.     begin
  727.       if (SelectedColorSquare.X = 0) and (SelectedColorSquare.Y = 0) then
  728.         AColor := FOtherColor
  729.       else
  730.         AColor := FPaletteColors[SelectedColorSquare.x, SelectedColorSquare.Y];
  731.       FSetParentColor(Self, AColor);
  732.     end;
  733.   end;
  734.   Close;
  735. end;
  736.  
  737. function TDFSColorButtonPalette.GetCurrentSquare: TPoint;
  738.  
  739.   function IsOtherColorSquare(Pt: TPoint): boolean;
  740.   begin
  741.     Result := (Pt.X >= ClientWidth-19) and (Pt.X <= ClientWidth-1) and
  742.        (Pt.Y >= 96) and (Pt.Y <= 113);
  743.   end;
  744.  
  745. var
  746.   CurPos: TPoint;
  747. begin
  748.   GetCursorPos(CurPos);
  749.   CurPos := ScreenToClient(CurPos);
  750.   Result := Point((CurPos.X div 18) + 1, (CurPos.Y div 18) + 1);
  751.   if IsOtherColorSquare(CurPos) then
  752.     Result := Point(0,0)
  753.   else if not ValidColorIndex(Result.X, Result.Y) then
  754.     Result := Point(-1,-1);
  755. end;
  756.  
  757. procedure TDFSColorButtonPalette.FormKeyPress(Sender: TObject;
  758.   var Key: Char);
  759. begin
  760.   if Key = #27 then
  761.     Close;
  762. end;
  763.  
  764. procedure TDFSColorButtonPalette.FormDestroy(Sender: TObject);
  765. begin
  766.   Application.OnDeactivate := FOldAppDeactivate;
  767. end;
  768.  
  769. procedure TDFSColorButtonPalette.SetPaletteColors(Value: TPaletteColors);
  770. begin
  771.   FPaletteColors.Assign(Value);
  772. end;
  773.  
  774. procedure TDFSColorButtonPalette.SetCustomColors(Value: TCustomColors);
  775. begin
  776.   FCustomColors.Assign(Value);
  777. end;
  778.  
  779.  
  780. end.
  781.